package jehc.djshi.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import jehc.djshi.common.base.BaseResult;
import jehc.djshi.common.base.BaseService;
import jehc.djshi.common.idgeneration.SnowflakeIdWorker;
import jehc.djshi.common.util.ExceptionUtil;
import jehc.djshi.common.util.StringUtil;
import jehc.djshi.common.util.file.FileUtil;
import jehc.djshi.file.dao.XtAttachmentDao;
import jehc.djshi.file.model.XtAttachment;
import jehc.djshi.workflow.design.MxGraphModel;
import jehc.djshi.workflow.design.MxGraphToBPMN;
import jehc.djshi.workflow.design.MxGraphToPng;
import jehc.djshi.workflow.model.LcNodeAttribute;
import jehc.djshi.workflow.param.LcHisParam;
import jehc.djshi.workflow.param.LcProcessParam;
import jehc.djshi.workflow.service.LcDeploymentHisService;
import jehc.djshi.workflow.service.LcNodeAttributeService;
import jehc.djshi.workflow.service.LcTaskService;
import jehc.djshi.workflow.util.ActivitiUtil;
import jehc.djshi.workflow.dao.LcDeploymentHisDao;
import jehc.djshi.workflow.dao.LcProcessDao;
import jehc.djshi.workflow.model.LcDeploymentHis;
import jehc.djshi.workflow.model.LcProcess;
import jehc.djshi.workflow.service.LcProcessService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.repository.Deployment;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Desc 流程信息存储记录
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Service
@Slf4j
public class LcProcessServiceImpl extends BaseService implements LcProcessService {
	@Autowired
	private LcProcessDao lcProcessDao;

	@Autowired
	private LcDeploymentHisDao lcDeploymentHisDao;

	@Autowired
	private ActivitiUtil activitiUtil;

	@Autowired
	private XtAttachmentDao xtAttachmentDao;

	@Autowired
	private LcDeploymentHisService lcDeploymentHisService;

	@Autowired
	private LcNodeAttributeService lcNodeAttributeService;

	@Autowired
	private LcTaskService lcTaskService;

	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;
	/**
	* 分页
	* @param condition 
	* @return
	*/
	public List<LcProcess> getLcProcessListByCondition(Map<String,Object> condition){
		try{
			return lcProcessDao.getLcProcessListByCondition(condition);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}
	/**
	* 查询对象
	* @param lc_process_id 
	* @return
	*/
	public LcProcess getLcProcessById(String lc_process_id){
		try{
			return lcProcessDao.getLcProcessById(lc_process_id);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}
	/**
	* 添加
	* @param lcProcess
	* @return
	*/
	public int addLcProcess(LcProcess lcProcess){
		int i = 0;
		try {
            lcProcess.setCreate_time(getDate());
			lcProcess.setCreate_id(getXtUid());
			i = lcProcessDao.addLcProcess(lcProcess);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return i;
	}

	/**
	* 修改
	* @param lcProcess
	* @return
	*/
	public int updateLcProcess(LcProcess lcProcess){
		int i = 0;
		try {
			lcProcess.setUpdate_time(getDate());
			lcProcess.setUpdate_id(getXtUid());
			i = lcProcessDao.updateLcProcess(lcProcess);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return i;
	}

	/**
	* 删除
	* @param condition 
	* @return
	*/
	public int delLcProcess(Map<String,Object> condition){
		int i = 0;
		try {
			i = lcProcessDao.delLcProcess(condition);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return i;
	}

	/**
	* 批量添加
	* @param lcProcessList
	* @return
	*/
	public int addBatchLcProcess(List<LcProcess> lcProcessList){
		int i = 0;
		try {
			i = lcProcessDao.addBatchLcProcess(lcProcessList);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return i;
	}

	/**
	* 批量修改
	* @param lcProcessList
	* @return
	*/
	public int updateBatchLcProcess(List<LcProcess> lcProcessList){
		int i = 0;
		try {
			i = lcProcessDao.updateBatchLcProcess(lcProcessList);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return i;
	}

	/**
	 * 发布或关闭流程
	 * @param condition
	 * @return
	 */
	public int updateLcProcessStatus(String lc_process_id,Map<String,Object> condition){
		int i = 0;
		try {
			String attachPath;
			if(StringUtil.isEmpty(lc_process_id)){
				throw new ExceptionUtil("流程编号为空");
			}
			LcProcess lcProcess = lcProcessDao.getLcProcessById(lc_process_id);
			if(null== lcProcess){
				throw new ExceptionUtil("该流程为空，无法发布");
			}
			if(1==lcProcess.getLc_process_status()){
				throw new ExceptionUtil("该流程已启动中，无法发布");
			}
			String versionPath = "";
			if(null != lcProcess.getVersion()){
				versionPath = lcProcess.getVersion()+"/";
			}
			Deployment deployment = null;
			if(1==lcProcess.getLc_process_flag()){//如果上传部署则
				XtAttachment xtAttachment = xtAttachmentDao.getXtAttachmentById(lcProcess.getXt_attachment());
				attachPath = FileUtil.validOrCreateFile(getXtPathCache("ActivitiLc").get(0).getXt_path()+versionPath+xtAttachment.getXt_attachmentName());
				File file = new File(attachPath);
				if(!file.exists()){
					throw new ExceptionUtil("流程文件不存在，部署失败");
				}
				deployment = activitiUtil.createDeployment(file);
			}else{
				deployment = activitiUtil.createDeployment(lcProcess.getLc_process_title(),lcProcess.getLc_process_bpmn());//通过bpmn字符串部署
			}
			if(null != deployment){
				LcDeploymentHis lcDeploymentHis = new LcDeploymentHis();
				lcDeploymentHis.setId(toUUID());
				lcDeploymentHis.setLc_deployment_his_id(deployment.getId());
				lcDeploymentHis.setLc_deployment_his_name(lcProcess.getLc_process_title()+"_"+deployment.getId());
				lcDeploymentHis.setLc_deployment_his_tenantId(deployment.getTenantId());
				lcDeploymentHis.setLc_deployment_his_time(getDate());
				lcDeploymentHis.setLc_process_id(lc_process_id);
				lcDeploymentHis.setLc_deployment_his_status(0);
				lcDeploymentHis.setVersion(lcProcess.getVersion());
				lcDeploymentHis.setUid(lcProcess.getLc_process_uid());
				lcDeploymentHis.setUk(lcProcess.getLc_process_uk());
				lcDeploymentHis.setLc_process_bpmn(lcProcess.getLc_process_bpmn());
				lcDeploymentHis.setLc_process_mxgraph_style(lcProcess.getLc_process_mxgraph_style());
				lcDeploymentHis.setLc_process_mxgraphxml(lcProcess.getLc_process_mxgraphxml());
				lcDeploymentHis.setImgxml(lcProcess.getImgxml());
				lcDeploymentHis.setH(lcProcess.getH());
				lcDeploymentHis.setW(lcProcess.getW());
				lcDeploymentHis.setCreate_id(getXtUid());
				lcDeploymentHis.setCreate_time(getDate());
				lcDeploymentHis.setCandidate_group_type(lcProcess.getCandidate_group_type());
				lcDeploymentHis.setCandidateStarterGroups(lcProcess.getCandidateStarterGroups());
				lcDeploymentHis.setCandidateStarterUsers(lcProcess.getCandidateStarterUsers());
				lcDeploymentHisDao.addLcDeploymentHis(lcDeploymentHis);
				syncAttr(lcDeploymentHis);//同步节点至版本中
			}else{
				throw new ExceptionUtil("返回流程部署信息为空");
			}
			i = lcProcessDao.updateLcProcessStatus(condition);
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return i;
	}

	/**
	 * 根据流程模块Key查找流程定义
	 * @param moduleKey
	 * @return
	 */
	public LcProcess getLcProcessByModuleKey(String moduleKey){
		return lcProcessDao.getLcProcessByModuleKey(moduleKey);
	}

	/**
	 * 根据模块Key发起流程实例
	 * @param lcHisParam
	 * @return
	 */
	public BaseResult start(LcHisParam lcHisParam){
		BaseResult baseResult = new BaseResult();
		String moduleKey = lcHisParam.getModuleKey();
		LcProcess lcProcess = getLcProcessByModuleKey(moduleKey);
		if(null == lcProcess){
			return new BaseResult("未能获取到模块key",false,null);
		}
		Map<String,Object> condition = new HashMap<>();
		condition.put("lc_process_id",lcProcess.getLc_process_id());
		LcDeploymentHis lcDeploymentHis = lcDeploymentHisService.getLcDeploymentHisNewUnique(condition);
		if(null == lcDeploymentHis){
			baseResult.setMessage("未能获取到最新流程版本");
			baseResult.setSuccess(false);
			return baseResult;
		}
		lcHisParam.setHid_(lcDeploymentHis.getId());
		BaseResult result = lcTaskService.start(lcHisParam);
		return result;
	}

	/**
	 * 在线设计
	 * @param mxGraphModel
	 * @param request
	 * @param response
	 * @return
	 */
	public synchronized BaseResult<LcProcess> create(MxGraphModel mxGraphModel, HttpServletRequest request, HttpServletResponse response){
		if(StringUtil.isEmpty(mxGraphModel.getProcessName())){
			return new BaseResult("流程标题为空",false);
		}
		BaseResult baseResult = new BaseResult();
		String mxgraphxml = mxGraphModel.getMxgraphxml();
		String imgxml = mxGraphModel.getImgxml();
		mxGraphModel.setMxgraphxml(mxgraphxml);
		mxGraphModel.setImgxml(imgxml);
		MxGraphToBPMN mxGraphToBPMN = new MxGraphToBPMN();
		mxGraphModel = mxGraphToBPMN.createBPMN(mxGraphModel);
		LcProcess lcProcess = new LcProcess();
		//////////添加或修改流程信息///////////////
		lcProcess.setLc_process_flag(0);
		lcProcess.setLc_process_bpmn(mxGraphModel.getBpmn());
		lcProcess.setLc_process_uid(mxGraphModel.getProcessId());
		lcProcess.setLc_process_uk(mxGraphModel.getProcessId());
		lcProcess.setLc_process_remark(mxGraphModel.getRemark());
		lcProcess.setLc_process_mxgraphxml(mxGraphModel.getMxgraphxml());
		lcProcess.setLc_process_status(0);
		lcProcess.setLc_process_title(mxGraphModel.getProcessName());
		lcProcess.setImgxml(mxGraphModel.getImgxml());
		lcProcess.setLc_process_id(mxGraphModel.getLc_process_id());
		lcProcess.setLc_product_id(mxGraphModel.getLc_product_id());
		lcProcess.setLc_group_id(mxGraphModel.getLc_group_id());
		lcProcess = generateBpmnAndImg(request.getRequestURL().toString(), imgxml, mxGraphModel.getBpmn(), mxGraphModel.getProcessName(), mxGraphModel.getW(), mxGraphModel.getH(), response, lcProcess);
		lcProcess.setLc_process_bpmn_path(lcProcess.getLc_process_bpmn_path());
		lcProcess.setLc_process_path(lcProcess.getLc_process_path());
		lcProcess.setLc_process_img_path(lcProcess.getLc_process_img_path());
		lcProcess.setH(mxGraphModel.getH());
		lcProcess.setW(mxGraphModel.getW());
		lcProcess.setModuleKey(StringUtil.isEmpty(mxGraphModel.getModuleKey())?genModuleKey():mxGraphModel.getModuleKey());
		lcProcess.setCandidateStarterGroups(mxGraphModel.getCandidateStarterGroups());
		lcProcess.setCandidateStarterUsers(mxGraphModel.getCandidateStarterUsers());
		lcProcess.setCandidate_group_type(mxGraphModel.getCandidate_group_type());
		int i = 0;
		if(StringUtils.isEmpty(lcProcess.getLc_process_id())){
			lcProcess.setLc_process_id(toUUID());
			i = addLcProcess(lcProcess);
		}else{
			i = updateLcProcess(lcProcess);
		}
		doAttr(lcProcess);//处理节点规则
		baseResult.setData(lcProcess);
		if(i > 0){
			baseResult.setSuccess(true);
			baseResult.setMessage("保存流程成功");
			return baseResult;
		}
		baseResult.setSuccess(false);
		baseResult.setMessage("保存流程失败");
		return baseResult;
	}

	/**
	 * 生成bpmn,图片两个文件及压缩文件
	 * @param url
	 * @param imgxml
	 * @param bpmn
	 * @param processName
	 * @param w
	 * @param h
	 * @param response
	 * @param lcProcess
	 * @return
	 */
	public LcProcess generateBpmnAndImg(String url, String imgxml, String bpmn, String processName, String w, String h, HttpServletResponse response, LcProcess lcProcess) {
		int version = reBuild(lcProcess);
		lcProcess.setVersion(version);
		String versionPath = "";
		if(null != lcProcess.getVersion()){
			versionPath = lcProcess.getVersion()+"/";
		}
		String attachPath = FileUtil.validOrCreateFile(getXtPathCache("ActivitiLc").get(0).getXt_path()+processName+"/"+versionPath);
		//生成BPMN文件
		String bpmnAttachPath = attachPath+processName+".bpmn";
		String imgAttachPath =  attachPath+processName+".png";
		try {
			OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(bpmnAttachPath),"UTF8");
			out.write(bpmn);
			out.flush();
			out.close();
		} catch (IOException e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		//通过mxgraphxml字符串生成PNG图片
		MxGraphToPng MxGraphToPng = new MxGraphToPng();
		int j = MxGraphToPng.mxgraphxmlToPng(url,imgxml,imgAttachPath,w,h,response);
		if(j <= 0){
			throw new ExceptionUtil("由bpmn文件生成图片失败");
		}
		//生成ZIP文件
		try{
			File jpdlAttachPathFile = new File(bpmnAttachPath);
			File imgAttachPathFile = new File(imgAttachPath);
			File zipFile = new File(attachPath+processName+".zip");
			File[] srcfile={jpdlAttachPathFile,imgAttachPathFile};
			FileUtil.zipFiles(srcfile,zipFile);
			lcProcess.setLc_process_bpmn_path(processName+".bpmn");
			lcProcess.setLc_process_path(processName+".zip");
			lcProcess.setLc_process_img_path(processName+".png");
		}catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
		return lcProcess;
	}

	/**
	 * 设置版本
	 * @param lcProcess
	 */
	private synchronized int reBuild(LcProcess lcProcess){
		if(!StringUtil.isEmpty(lcProcess.getLc_process_id())){
			Integer maxVersion = lcDeploymentHisDao.getMaxVersionByProcessId(lcProcess.getLc_process_id());
			if(null != maxVersion) {//如果发布中流程进行重新设计 则生成文件需要重新生成并加上版本号
				return (maxVersion.intValue() + 1);
			}
		}
		return 0;
	}

	/**
	 * 复制
	 * @param lcProcessParam
	 * @return
	 */
	public BaseResult copy(LcProcessParam lcProcessParam, HttpServletRequest request, HttpServletResponse response){
		if(StringUtil.isEmpty(lcProcessParam.getLc_process_id())){
			return new BaseResult("未能获取到流程id",false);
		}
		if(StringUtil.isEmpty(lcProcessParam.getLc_process_title())){
			return new BaseResult("流程标题为空",false);
		}
		if(StringUtil.isEmpty(lcProcessParam.getModuleKey())){
			return new BaseResult("流程模块Key为空",false);
		}
		LcProcess lcProcess = getLcProcessById(lcProcessParam.getLc_process_id());
		if(null == lcProcess){
			return new BaseResult("未能获取到流程对象",false);
		}
		Map<String,Object> condition = new HashMap<>();
		condition.put("moduleKey",lcProcessParam.getModuleKey());
		List<LcProcess> list = lcProcessDao.getLcProcessListByCondition(condition);
		if(!CollectionUtil.isEmpty(list)){
			return new BaseResult("流程模块Key已存在",false);
		}
		MxGraphModel mxGraphModel = new MxGraphModel();
		mxGraphModel.setBpmn(null);
		mxGraphModel.setCandidate_group_type(lcProcess.getCandidate_group_type());
		mxGraphModel.setImgxml(lcProcess.getImgxml());
		mxGraphModel.setMxgraphxml(lcProcess.getLc_process_mxgraphxml());
		mxGraphModel.setW(lcProcess.getW());
		mxGraphModel.setH(lcProcess.getH());
		mxGraphModel.setLc_process_id(null);
		mxGraphModel.setCandidateStarterGroups(lcProcess.getCandidateStarterGroups());
		mxGraphModel.setCandidateStarterUsers(lcProcess.getCandidateStarterUsers());
		mxGraphModel.setRemark(lcProcess.getLc_process_remark());
		mxGraphModel.setModuleKey(lcProcessParam.getModuleKey());
		mxGraphModel.setLc_product_id(lcProcessParam.getLc_product_id());
		mxGraphModel.setLc_group_id(lcProcessParam.getLc_group_id());
		mxGraphModel.setProcessName(lcProcessParam.getLc_process_title());
		BaseResult<LcProcess> baseResult = create(mxGraphModel,request,response);
		if(!baseResult.getSuccess()){
			return BaseResult.fail("复制主数据异常");
		}
		if(0 == lcProcessParam.getSyncAttr()){
			//同步扩展属性
			condition = new HashMap<>();
			condition.put("mounts_id",lcProcessParam.getLc_process_id());
			List<LcNodeAttribute> lcNodeAttributes = lcNodeAttributeService.getLcNodeAttributeListByCondition(condition);
			if(!CollectionUtil.isEmpty(lcNodeAttributes)){
				for(LcNodeAttribute lcNodeAttribute: lcNodeAttributes){
					lcNodeAttribute = lcNodeAttributeService.getLcNodeAttributeById(lcNodeAttribute.getLc_node_attribute_id());
					lcNodeAttribute.setMounts_id(baseResult.getData().getLc_process_id());
					lcNodeAttribute.setLc_node_attribute_id(null);
					lcNodeAttribute.setHid_(null);
					lcNodeAttribute.setLc_process_id(baseResult.getData().getLc_process_id());
					lcNodeAttributeService.saveLcNodeAttribute(lcNodeAttribute);
				}
			}
		}
		return BaseResult.success();
	}

	/**
	 * 同步主节点配置信息至子表中
	 * @param lcDeploymentHis
	 */
	private void syncAttr(LcDeploymentHis lcDeploymentHis){
		String hid = lcDeploymentHis.getId();
		if(!StringUtil.isEmpty(lcDeploymentHis.getLc_process_id()) && !StringUtil.isEmpty(hid)){
			Map<String,Object> condition = new HashMap<>();
			condition.put("mounts_id",lcDeploymentHis.getLc_process_id());
			List<LcNodeAttribute> lcNodeAttributes = lcNodeAttributeService.getLcNodeAttributeListByCondition(condition);
			if(!CollectionUtil.isEmpty(lcNodeAttributes)){
				for(LcNodeAttribute lcNodeAttribute: lcNodeAttributes){
					lcNodeAttribute = lcNodeAttributeService.getLcNodeAttributeById(lcNodeAttribute.getLc_node_attribute_id());
					lcNodeAttribute.setMounts_id(null);
					lcNodeAttribute.setLc_node_attribute_id(null);
					lcNodeAttribute.setHid_(hid);
					lcNodeAttributeService.saveLcNodeAttribute(lcNodeAttribute);
				}
			}
		}
	}

	/**
	 * 处理节点
	 * @param lcProcess
	 */
	private void doAttr(LcProcess lcProcess){
		//如果节点已被删除则需要删除已配置的节点规则
		if(null != lcProcess){
			String bpmn = lcProcess.getLc_process_bpmn();
			if(!StringUtil.isEmpty(bpmn)){
				List<UserTask> userTasks = activitiUtil.getUserTaskElementsByBpmn(bpmn);
				List<String> nodeIds = new ArrayList<>();
				if(!CollectionUtil.isEmpty(userTasks)){
					for(UserTask userTask: userTasks){
						nodeIds.add(userTask.getId());
					}
				}
				Map<String,Object> condition = new HashMap<>();
				if(!CollectionUtil.isEmpty(nodeIds)){
					condition.put("nodeId",StringUtils.join(nodeIds.toArray(),","));
				}
				condition.put("mounts_id",lcProcess.getLc_process_id());
				List<LcNodeAttribute> lcNodeAttributes = lcNodeAttributeService.getLcNodeAttributeListByCondition(condition);
				List<LcNodeAttribute> newLcNodeAttributes = new ArrayList<>();
				if(!CollectionUtil.isEmpty(lcNodeAttributes)){
					for(LcNodeAttribute lcNodeAttribute : lcNodeAttributes){
						lcNodeAttribute = lcNodeAttributeService.getLcNodeAttributeById(lcNodeAttribute.getLc_node_attribute_id());
						newLcNodeAttributes.add(lcNodeAttribute);
					}
				}
				condition = new HashMap<>();
				condition.put("mounts_id",lcProcess.getLc_process_id());
				List<LcNodeAttribute> oldLcNodeAttributes = lcNodeAttributeService.getLcNodeAttributeListByCondition(condition);//原始数据

				if(!CollectionUtil.isEmpty(oldLcNodeAttributes)){
					//删除当前流程下的所有已配置节点规则
					for(LcNodeAttribute lcNodeAttribute : oldLcNodeAttributes){
						lcNodeAttributeService.delLcNodeAttributeById(lcNodeAttribute.getLc_node_attribute_id());
					}
				}
				if(!CollectionUtil.isEmpty(newLcNodeAttributes)){//重新新增
					for(LcNodeAttribute lcNodeAttribute: newLcNodeAttributes){
						lcNodeAttribute.setLc_node_attribute_id(null);
						lcNodeAttributeService.saveLcNodeAttribute(lcNodeAttribute);
					}
				}
			}
		}
	}

	/**
	 * 生成模块Key
	 * @return
	 */
	private synchronized String genModuleKey(){
		return ""+snowflakeIdWorker.nextId();
	}
}
